package cn.thoughtworks.school.services;


import cn.thoughtworks.school.entities.*;
import cn.thoughtworks.school.entities.OnlineLanguageQuiz;
import cn.thoughtworks.school.entities.dto.AssignmentQuizData;
import cn.thoughtworks.school.repositories.OnlineLanguageQuizRepository;
import cn.thoughtworks.school.repositories.UserQuizGroupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OnlineLanguageQuizService {
  @Autowired
  private OnlineLanguageQuizRepository onlineLanguageQuizRepository;
  @Autowired
  private UserQuizGroupRepository userQuizGroupRepository;
  @Autowired
  private Utils utils;
  @Autowired
  private QuizService quizService;
  @Autowired
  private UserCenterService userCenterService;

  public Page getOnlineLanguageQuizzes(String status, String type, String content, Pageable pageable, User user) {
    List<Long> groupIds = quizService.getGroupIdsByUserId(user.getId());
    if (hasContent(status)) {
      Page<OnlineLanguageQuiz> onlineLanguageQuizPage = getAllOnlineLanguageQuizzesByStatus(Integer.parseInt(status), type, content, pageable, groupIds);
      return utils.format(onlineLanguageQuizPage, pageable);
    }
    Page<OnlineLanguageQuiz> onlineLanguageQuizPage = getAllOnlineLanguageQuizzes(type, content, pageable, groupIds);
    return utils.format(onlineLanguageQuizPage, pageable);
  }

  private Page<OnlineLanguageQuiz> getAllOnlineLanguageQuizzes(String type, String content, Pageable pageable, List<Long> groupIds) {
    if (hasContent(content)) {
      if (isEquals(type, "tags")) {
        String[] tagNames = content.split(",");
        return onlineLanguageQuizRepository
          .findAllByIsAvailableAndTagAndQuizGroupIdIn(tagNames, groupIds, pageable);
      }
      if (isEquals(type, "makerId")) {
        return onlineLanguageQuizRepository
          .findAllByIsAvailableIsTrueAndMakerIdAndQuizGroupIdIn(Long.valueOf(content), groupIds, pageable);
      }
      if (isEquals(type, "quizId")) {
        return onlineLanguageQuizRepository
          .findAllByIdAndQuizGroupIdIn(Long.valueOf(content), groupIds, pageable);
      }
      if (isEquals(type, "remark")) {
        return onlineLanguageQuizRepository
          .findByRemarkLikeAndIsAvailableAndQuizGroupIdIn("%" + content + "%", true, groupIds, pageable);
      }
      if (isEquals(type, "quizName")) {
        return onlineLanguageQuizRepository
          .findByOnlineLanguageNameLikeAndIsAvailableAndQuizGroupIdIn("%" + content + "%", true, groupIds, pageable);
      }
      if (isEquals(type, "description")) {
        return onlineLanguageQuizRepository
          .findByDescriptionLikeAndIsAvailableAndQuizGroupIdIn("%" + content + "%", true, groupIds, pageable);
      }
    }
    return onlineLanguageQuizRepository
      .findAllByIsAvailableIsTrueAndQuizGroupIdIn(groupIds, pageable);
  }

  private Page<OnlineLanguageQuiz> getAllOnlineLanguageQuizzesByStatus(int status, String type, String content, Pageable pageable, List<Long> groupIds) {
    if (hasContent(content)) {
      if (isEquals(type, "tags")) {
        String[] tagNames = content.split(",");
        return onlineLanguageQuizRepository
          .findAllByIsAvailableAndTagAndStatusAndQuizGroupIdIn(tagNames, status, groupIds, pageable);
      }
      if (isEquals(type, "makerId")) {
        return onlineLanguageQuizRepository
          .findAllByIsAvailableIsTrueAndMakerIdAndStatusAndQuizGroupIdIn(Long.valueOf(content), status, groupIds, pageable);
      }
      if (isEquals(type, "quizId")) {
        return onlineLanguageQuizRepository
          .findAllByIdAndStatusAndQuizGroupIdIn(Long.valueOf(content), status, groupIds, pageable);
      }
      if (isEquals(type, "remark")) {
        return onlineLanguageQuizRepository
          .findByRemarkLikeAndIsAvailableAndStatusAndQuizGroupIdIn("%" + content + "%", true, status, groupIds, pageable);
      }
      if (isEquals(type, "quizName")) {
        return onlineLanguageQuizRepository
          .findByOnlineLanguageNameLikeAndIsAvailableAndStatusAndQuizGroupIdIn("%" + content + "%", true, status, groupIds, pageable);
      }
      if (isEquals(type, "description")) {
        return onlineLanguageQuizRepository
          .findByDescriptionLikeAndIsAvailableAndStatusAndQuizGroupIdIn("%" + content + "%", true, status, groupIds, pageable);
      }
    }
    return onlineLanguageQuizRepository
      .findAllByIsAvailableIsTrueAndStatusAndQuizGroupIdIn(status, groupIds, pageable);
  }

  private boolean isEquals(String type, String value) {
    return Objects.equals(type, value);
  }

  private boolean hasContent(String content) {
    return !content.equals("");
  }

  public Page getQuizzesPageable(Pageable pageable, Long id, Long userId, String description, List<String> tags, User user) {
    Long currentOrganizationId = userCenterService.getUserCurrentOrganizationId(user.getId());
    List<Long> quizIds = getQuizIdsByTags(tags);
    Page<OnlineLanguageQuiz> homeworkQuizPage = getOnlineLanguageQuizPage(currentOrganizationId, pageable, id, userId, description, quizIds);

    return utils.format(homeworkQuizPage, pageable);
  }

  private Page<OnlineLanguageQuiz> getOnlineLanguageQuizPage(Long organizationId, Pageable pageable, Long id, Long userId, String description, List<Long> quizIds) {
    return onlineLanguageQuizRepository.findAll((Specification<OnlineLanguageQuiz>) (root, query, criteriaBuilder) -> {
      List<Predicate> predicates = quizService.getDefaultPredicates(organizationId, id, userId, description, quizIds, root, criteriaBuilder);
      return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
    }, pageable);
  }

  private List<Long> getQuizIdsByTags(List<String> tags) {
    List<OnlineLanguageQuiz> quizzes = onlineLanguageQuizRepository.findQuizzesByTags(tags);
    if (Objects.nonNull(tags) && quizzes.isEmpty()) {
      return Arrays.asList(-1L);
    }
    return quizzes.stream().map(OnlineLanguageQuiz::getId).collect(Collectors.toList());
  }

  public List<AssignmentQuizData> copy(List<AssignmentQuizData> onlineLanguageQuizzesData) {
    List<Long> ids = onlineLanguageQuizzesData.stream().map(AssignmentQuizData::getQuizId).collect(Collectors.toList());
    List<OnlineLanguageQuiz> onlineLanguageQuizzes = onlineLanguageQuizRepository.findByIdIn(ids);
    return onlineLanguageQuizzesData.stream().map(quizData -> {
      Long creatorId = quizData.getCreatorId();
      OnlineLanguageQuiz onlineLanguageQuiz = onlineLanguageQuizzes.stream()
        .filter(quiz -> quiz.getId().equals(quizData.getQuizId()))
        .findFirst().get();
      Set<Tag> tags = quizService.copyTags(quizData.getOrganizationId(), onlineLanguageQuiz.getTags(), creatorId);
      Long stackId = quizService.copyStack(quizData.getOrganizationId(), onlineLanguageQuiz.getStackId(), creatorId);
      onlineLanguageQuiz = OnlineLanguageQuiz.copy(onlineLanguageQuiz, creatorId, quizData.getOrganizationId(),tags,stackId);
      onlineLanguageQuizRepository.save(onlineLanguageQuiz);
      quizData.setNewQuizId(onlineLanguageQuiz.getId());
      return quizData;
    }).collect(Collectors.toList());

  }
}
